/*
 * boa.c
 *
 *  Created on: 2014-8-11
 *      Author: root
 */
#include <sys/resource.h>

#include "onvif/nsmap.h"
#include "onvif/onvifH.h"
#include "onvif/onvifStub.h"
//#include "onvif/stdsoap2.h"
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <signal.h>
#include <sys/sem.h>
#include <sys/ipc.h>
#include "boa.h"
#include "interface/boa_interface.h"

#define ONVIF_LISTEN_PORT	3702
//单独程序测试宏
//#define EXE

#ifndef EXE
extern pthread_t	g_OnvifUdpServerThreadHandle;//OnvifUdpServer线程句柄
extern int32 g_exitOnvifUdpServerThread;		//OnvifUdpServer线程结束标记
#else
pthread_t	g_OnvifUdpServerThreadHandle;//OnvifUdpServer线程句柄
int32 g_exitOnvifUdpServerThread = 1;		//OnvifUdpServer线程结束标记
#endif

pthread_t	g_BoaServerThreadHandle;//BoaServer线程句柄
int32 g_exitBoaServerThread = 1;		//BoaServer线程结束标记


int backlog = SO_MAXCONN;
int devnullfd = -1;
time_t start_time;

int sighup_flag = 0;            /* 1 => signal has happened, needs attention */
int sigchld_flag = 0;           /* 1 => signal has happened, needs attention */
int sigalrm_flag = 0;           /* 1 => signal has happened, needs attention */
int sigterm_flag = 0;           /* lame duck mode */
time_t current_time;
int max_fd = 0;
int pending_requests = 0;
int g_boaStatus = 1;
Onvif_Config_Data onvifConfig;

static int sock_opt = 1;
static int do_fork = 1;

/*BoaServer_thread_start
 * Name: fixup_server_root
 *
 * Description: Makes sure the server root is valid.
 *
 */

static void fixup_server_root()
{
    char *dirbuf;

    if (!server_root) {
#ifdef SERVER_ROOT
        server_root = strdup(SERVER_ROOT);
        if (!server_root) {
            perror("strdup (SERVER_ROOT)");
            exit(1);
        }
#else
        fputs("boa: don't know where server root is.  Please #define "
              "SERVER_ROOT in boa.h\n"
              "and recompile, or use the -c command line option to "
              "specify it.\n", stderr);
        exit(1);
#endif
    }

    if (chdir(server_root) == -1) {
        fprintf(stderr, "Could not chdir to \"%s\": aborting\n",
                server_root);
        exit(1);
    }

    dirbuf = normalize_path(server_root);
    free(server_root);
    server_root = dirbuf;
}

static int create_server_socket(void)
{
    int server_s;

    server_s = socket(SERVER_AF, SOCK_STREAM, IPPROTO_TCP);
    if (server_s == -1) {
        DIE("unable to create socket");
    }

    /* server socket is nonblocking */
    if (set_nonblock_fd(server_s) == -1) {
        DIE("fcntl: unable to set server socket to nonblocking");
    }

    /* close server socket on exec so cgi's can't write to it */
    if (fcntl(server_s, F_SETFD, 1) == -1) {
        DIE("can't set close-on-exec on server socket!");
    }

    /* reuse socket addr */
    if ((setsockopt(server_s, SOL_SOCKET, SO_REUSEADDR, (void *) &sock_opt,
                    sizeof (sock_opt))) == -1) {
        DIE("setsockopt");
    }

    /* internet family-specific code encapsulated in bind_server()  */
    if (bind_server(server_s, server_ip) == -1) {
        DIE("unable to bind");
    }

    /* listen: large number just in case your kernel is nicely tweaked */
    if (listen(server_s, backlog) == -1) {
        DIE("unable to listen");
    }
    return server_s;
}

/*lxfun 2014-8-11
函数名称：	OnvifUdpServer_thread_start
函数功能：	支持onvif udp 扫描
参数：		未用
返回值：		未用
*/
int32 OnvifUdpServer_thread_start()
{
	memset(&g_OnvifUdpServerThreadHandle, 0, sizeof(g_OnvifUdpServerThreadHandle));
	g_exitOnvifUdpServerThread = 1;

	if((pthread_create(&g_OnvifUdpServerThreadHandle, NULL, (void *)&OnvifUdpServer_thread_proc, NULL)) != 0)
	{
		printf("OnvifUdpServer_thread_start failed!\n");
		return -1;
	}

	return 0;
}

/*lxfun 2014-8-12
函数名称：	BoaServer_thread_start
函数功能：	建立ＢＯＡ服务器
参数：		未用
返回值：		未用
*/
int32 BoaServer_thread_start()
{
	memset(&g_BoaServerThreadHandle, 0, sizeof(g_BoaServerThreadHandle));
	g_exitBoaServerThread = 1;

	if((pthread_create(&g_BoaServerThreadHandle, NULL, (void *)&BoaServer_thread_proc, NULL)) != 0)
	{
		printf("BoaServer_thread_start failed!\n");
		return -1;
	}

	return 0;
}

void BoaServer_thread_proc()
{
    //获取boa配置文件和服务器根目录
	int c;
	int server_s;                   /* boa socket */
    fixup_server_root();
    read_config_files();

	//按boa配置文件配置ＢＯＡ服务器
    create_common_env();
    build_needs_escape();

    if (max_connections < 1) {
        struct rlimit rl;

        /* has not been set explicitly */
        c = getrlimit(RLIMIT_NOFILE, &rl);
        if (c < 0) {
            perror("getrlimit");
            exit(1);
        }
        max_connections = rl.rlim_cur;
    }
    //打印启动输出
    timestamp();

	server_s = create_server_socket();

	struct soap* soap;
	soap=soap_new();
	soap_init(soap);

	soap->master = server_s;
	soap->socket = server_s;
	soap->errmode = 0;
	soap->bind_flags = 1;
	fprintf(stderr,"%s----%s---%d\n\n",__FILE__,__func__,__LINE__);
	//启动ＢＯＡ服务器，接收并处理数据
	while(1)
	{
		select_loop(server_s,soap);
		usleep(100);
	}
	g_exitBoaServerThread = 0;
}

#ifdef EXE
void main()
{
    int server_s;                   /* boa socket */
    int c;

    //获取boa配置文件和服务器根目录
    fixup_server_root();
    read_config_files();

	//按boa配置文件配置ＢＯＡ服务器
    create_common_env();
    build_needs_escape();

    if (max_connections < 1) {
        struct rlimit rl;

        /* has not been set explicitly */
        c = getrlimit(RLIMIT_NOFILE, &rl);
        if (c < 0) {
            perror("getrlimit");
            exit(1);
        }
        max_connections = rl.rlim_cur;
    }

    //打印启动输出
    timestamp();

    //设置onvif参数
    OnvifParamInit(&onvifConfig);

    //建立设备扫描服务器?
    OnvifUdpServer_thread_start();

	server_s = create_server_socket();

	struct soap* soap;
	soap=soap_new();
	soap_init(soap);

	soap->master = server_s;
	soap->socket = server_s;
	soap->errmode = 0;
	soap->bind_flags = 1;
	fprintf(stderr,"%s----%s---%d\n\n",__FILE__,__func__,__LINE__);
	//启动ＢＯＡ服务器，接收并处理数据
	while(1)
	{
		select_loop(server_s,soap);
		usleep(100);
	}
}
#endif

void OnvifUdpServer_thread_proc()
{
	int count = 0;
	struct soap ServerSoap;
	struct ip_mreq mcast;

	soap_init1(&ServerSoap, SOAP_IO_UDP | SOAP_XML_IGNORENS);
	soap_set_namespaces(&ServerSoap,  namespaces);

	if(!soap_valid_socket(soap_bind(&ServerSoap, NULL, ONVIF_LISTEN_PORT, 10)))
	{
		soap_print_fault(&ServerSoap, stderr);
		exit(1);
	}

	mcast.imr_multiaddr.s_addr = inet_addr("239.255.255.250");
	mcast.imr_interface.s_addr = htonl(INADDR_ANY);

	if(setsockopt(ServerSoap.master, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char*)&mcast, sizeof(mcast)) < 0)
	{
		printf("setsockopt error! error code = %d,err string = %s\n",errno,strerror(errno));
		g_exitOnvifUdpServerThread = 0;
		return;
	}

	while(1)
	{
		if(soap_serve(&ServerSoap))
		{
			soap_print_fault(&ServerSoap, stderr);
		}
		soap_destroy(&ServerSoap);
		soap_end(&ServerSoap);

		fprintf(stderr,"RECEIVE count %d, connection from IP = %lu.%lu.%lu.%lu socket = %d \r\n",
				count, ((ServerSoap.ip)>>24)&0xFF, ((ServerSoap.ip)>>16)&0xFF, ((ServerSoap.ip)>>8)&0xFF, (ServerSoap.ip)&0xFF, (ServerSoap.socket));
		count++;
	}

	soap_done(&ServerSoap);
	return;
}
